'use strict';

var app = require('../../server/server');
var pattern = require('../pattern');
var winston = require('winston');

module.exports = function(Game) {

  Game.disableRemoteMethod('__count__actions', false);
  // Game.disableRemoteMethod('__create__actions', false);
  Game.disableRemoteMethod('__delete__actions', false);
  // Game.disableRemoteMethod('__destroyById__actions', false);
  Game.disableRemoteMethod('__findById__actions', false);
  // Game.disableRemoteMethod('__get__actions', false);
  // Game.disableRemoteMethod('__updateById__actions', false);

  Game.observe('before save', function initResults(ctx, next) {
    if (ctx.isNewInstance) {
      var game = ctx.instance;
      game.match(function (err, match) {
        console.log('=== new game in match: ===');
        console.log(match);
        if (!game.results) {
          game.results = [];
          for (var i = 0; i < match._players.length; i++) {
            game.results[i] = match._players[i];
            game.results[i]['score'] = 0;
          }
        }

        console.log('=== new game to save: ===');
        console.log(game);
        next();
      })
    } else {
      // should not calculateScore here, can only get currentInstance, which is readonly
      next();
    }
  });

  Game.observe('after save', function initResults(ctx, next) {
    if (!ctx.isNewInstance) {
      if (!ctx.options.updateScore) {
        var game = ctx.instance;
        game.match(function (err, match) {
          console.log('== update game in match: ===');
          console.log(match);
          setScorefromNull(game);
          if (match.rules.includes('带擦挂')) {
            AddCagua(match._players, game);
          }
          arrangePlayerPosition(game);
          clean(game);
          calculateScore(game);
          console.log(game.results);
          game.save({ updateScore: true }, null);

          // app.pushData(match.id, 'game', game);
          // app.broadcast('game', game)
          app.broadcastToSome('game', app.getClientsFromTable(match.tableId), game)
          next();

        })
      } else {
        // update score save
        next();
      }
    } else {
      var game = ctx.instance;
      // app.pushData(game.matchId, 'newGame', game);
      game.match(function(err, match) {
        app.broadcastToSome('newGame', app.getClientsFromTable(match.tableId), game)
        next()
      })
      // app.broadcast('newGame', game)
      // next();
    }
  });

  function clean(game) {
    game.results.forEach(function (result) {
      result.score = 0;
    })

    game._actions.forEach(function (action) {
      if (action.type == '杠') {
        action.unsetAttribute('returned');
        action.unsetAttribute('transferedTo');
      }
      action.initDisplayName();
    });
  }

  function AddCagua(players, game) {
    if (game._actions.length == 0) return;
    var latestAction = game._actions[game._actions.length - 1];
    if (latestAction.type == '杠' && latestAction.attributes[0] == '直杠') {
      latestAction.cagua = [];
      players.forEach(function (player) {
        if (!hasHued(game, player) && player.id != latestAction.owner.id && player.id != latestAction.targets[0].id) {
          console.log('擦挂 ' + player.name);
          latestAction.cagua.push({ id: player.id, name: player.name });
        }
      });
    }
  }

  function calculateScore(game) {
    console.log('=== calculateScore: ===');
    var base = game.match().base;
    var ceiling = game.match().ceiling;
    var rules = game.match().rules;
    console.log('base: ' + base + ', ceiling: ' + ceiling + ', rules: ' + rules);

    // 检查呼叫转移
    if (rules.includes('呼叫转移')) {
      var needTransfer = false;

      for (var i = game._actions.length - 1; i >= 0; i--) {
        var action = game._actions[i];

        var from, to;
        if (action.type == '胡' && action.attributes.includes('杠上炮')) {
          from = action.targets[0];
          to = action.owner;
          needTransfer = true;
          console.log('需要转雨');
        }

        if (needTransfer && action.type == '杠' && action.owner.id == from.id) {
          if (action.transferedTo == undefined) {
            action.transferedTo = to;
            action.displayName += '(已转给' + to.name + ')';
            console.log('已转给' + to.name);
          }
          needTransfer = false;
        }
      }
    }

    game._actions.forEach(action => calculateChajiao(game, action, base, ceiling));

    game._actions.forEach(action => calculateGang(game, action, base))

    game._actions.forEach(action => calculateHu(game, action, base, ceiling, rules));

  }

  function calculateHu(game, action, base, ceiling, rules) {
    var times = 1; // 倍数
    if (action.type == '胡') {
      console.log('胡:');
      console.log(action);
      if (action.attributes.includes('杠上花') && !action.attributes.includes('自摸')) {
        action.attributes.push('自摸');
        action.displayName += ' 自摸';
      }
      times *= pattern.calculateHuTimes(action.attributes);
      var huActionIndex = game._actions.indexOf(action);
      // 算杠
      for (var i = 0; i < huActionIndex; i++) {
        var a = game._actions[i];
        if (a.type == '杠' && a.owner.id == action.owner.id) {
          times *= 2;
        }
      }
      if (action.attributes.includes('自摸')) {
        if (rules.includes('自摸加番')) {
          times *= 2;
          times = Math.min(times, Math.pow(2, ceiling));
        } else {
          times = Math.min(times, Math.pow(2, ceiling));
          times += 1;
        }
      } else {
        times = Math.min(times, Math.pow(2, ceiling));
      }

      winScore(action.owner, action.targets, game, base * times);
      action.times = times;
      action.score = base * times;
    }
  }

  function calculateGang(game, action, base) {
    if (action.type == '杠' && !action.returned) {
      console.log('杠:');
      console.log(action);
      var winner;
      if (action.transferedTo) {
        winner = action.transferedTo;
      } else {
        winner = action.owner;
      }

      var rain = 0;
      if (action.attributes[0] == '暗杠') {
        rain = base * 2;
        action.times = 2;
      } else if (action.attributes[0] == '补杠') {
        rain = base * 1;
        action.times = 1;
      } else if (action.attributes[0] == '直杠') {
        rain = base * 2;
        action.times = 2;
        action.cagua && winScore(winner, action.cagua, game, base);
      }
      winScore(winner, action.targets, game, rain);
      action.score = rain;
    }
  }

  function calculateChajiao(game, action, base, ceiling) {
    if (action.type == '查叫') {
      console.log('查叫:');
      console.log(action);
      // 反雨
      returnRain(game, action.targets);
      var times = pattern.calculateHuTimes(action.attributes);
      // 算杠
      for (var i = 0; i < game._actions.length; i++) {
        var a = game._actions[i];
        if (a.type == '杠' && a.owner.id == action.owner.id) {
          times *= 2;
        }
      }

      times = Math.min(times, Math.pow(2, ceiling));
      winScore(action.owner, action.targets, game, base * times);
      action.times = times;
      action.score = base * times;
    }
  }

  function arrangePlayerPosition(game) {
    if (game._actions.length == 0) return;
    var latestAction = game._actions[game._actions.length - 1];
    if (latestAction.type != '胡') return;
    var HuedPlayer = latestAction.owner;

    var results = game.results;
    var fromIndex, toIndex;
    for (var i = 0; i < results.length; i++) {
      if (HuedPlayer.id == results[i].id) {
        fromIndex = i;
      }
      if (toIndex == undefined && !hasHued(game, results[i])) {
        toIndex = i;
      }
    }

    console.log('fromIndex: ' + fromIndex);
    console.log('toIndex: ' + toIndex);
    if (fromIndex > toIndex) {
      var removed = results.splice(fromIndex, 1)[0];
      results.splice(toIndex, 0, removed);
    }
  }

  function hasHued(game, player) {
    return game._actions.some(action => action.type == '胡' && action.owner.id == player.id)
  }

  function winScore(winner, losers, game, score) {
    winner = findPlayer(game, winner);
    losers.forEach(function (loser) {
      loser = findPlayer(game, loser)
      if (winner && loser) {
        winner.score += score;
        loser.score -= score;

        winner[`scorefrom_${loser.name}_${loser.id}`] += score
        loser[`scorefrom_${winner.name}_${winner.id}`] -= score
      }
      console.log(`=== winScore: ${winner.name} wins ${loser.name} ${score} ===`);
    });
  }

  function findPlayer(game, target) {
    return game.results.find(result => result.id == target.id)
  }

  function returnRain(game, losers) {
    losers.forEach(function (loser) {
      game._actions.forEach(function (action) {
        if (action.owner.id == loser.id && action.type == '杠' && !action.returned) {
          action.returned = true;
          action.displayName += '(已返雨)';
        }
      });
    });
  }

};

function setScorefromNull(game) {
  game.results.forEach( winner => {
    game.results.filter(loser => winner.id != loser.id + '').forEach( loser => {
      winner[`scorefrom_${loser.name}_${loser.id}`] = 0
    })
  })
}
